import io
from urllib.parse import quote

import xlwt
from django.http import HttpResponse

from backend.models import Emp, Dept


def get_style(name, *, color=0, bold=False, italic=False):
    """按照指定的参数获得单元格样式"""
    font = xlwt.Font()
    font.name = name
    font.colour_index = color
    font.bold = bold
    font.italic = italic
    style = xlwt.XFStyle()
    style.font = font
    return style


def export_excel(request):
    workbook = xlwt.Workbook()
    # 向工作簿中添加工作表
    sheet = workbook.add_sheet('员工信息表')
    # 设置表头
    titles = ('编号', '姓名', '职位', '主管', '部门')
    for col, title in enumerate(titles):
        sheet.write(0, col, title, get_style('HYj1gf', color=2, bold=True))
    props = ('no', 'name', 'job', 'mgr', 'dept')
    # 通过数据库获得的员工数据填写Excel表格
    # 如果一个对象关联了其他对象，Django的ORM框架在默认情况下会产生1+N查询问题
    # 可以使用下面的方法在查询时直接获取关联对象从而避免1+N查询：
    # - select_related('关联对象的属性名') - 解决多对一或一对一关联查询
    # - prefetch_related('关联对象的属性名') - 解决多对多关联查询
    # 使用这两个方法后生成的SQL语句会使用inner join或left outer join来避免多次查询
    # 可以使用QuerySet对象的only()方法指定要查询哪些属性
    # 可以使用QuerySet对象的defer()方法指定不查哪些属性
    queryset = Emp.objects.all().only('name', 'job', 'mgr', 'dept')\
        .select_related('mgr').select_related('dept')
    for row, emp in enumerate(queryset):
        for col, prop in enumerate(props):
            val = getattr(emp, prop, '')
            if isinstance(val, (Emp, Dept)):
                val = getattr(val, 'name', '')
            sheet.write(row + 1, col, val)
    # 将Excel工作簿写入内存
    buffer = io.BytesIO()
    workbook.save(buffer)
    # 通过HttpResponse（响应对象）将Excel的数据输出到浏览器
    resp = HttpResponse(buffer.getvalue())
    # 修改响应头设置内容类型（MIME类型）
    resp['content-type'] = 'application/vnd.ms-excel'
    # 将中文文件名处理成百分号编号（URL、请求行、请求头不支持非ASCII码字符）
    filename = quote('员工信息.xls')
    # 修改响应头设置浏览器如何处理内容
    resp['content-disposition'] = f'attachment; filename="{filename}"'
    return resp
